package model;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
import javax.swing.Timer;

/**
 *
 * @author Dustin
 */
public class SendWindow extends Thread {
    private int windowSize = 4;
    private int sequenceNumber = 0;
    private int sequenceBase = 0;
    private ReceiveWindow receiveWindow;
    private Queue outputQueue;
    private Queue dataQueue;
    private ArrayList<Packet> transmissionArray = new ArrayList<Packet>();
    private Timer timer;

    public SendWindow(Queue aQueue) {
        outputQueue = aQueue;
        dataQueue = new Queue();
        timer = new Timer(500, new TimerController());
        timer.start();
    }

    public void run() {
        while(true) {
            if(!dataQueue.isEmpty() && sequenceNumber < (sequenceBase + windowSize)) {
                Packet p = new Packet(sequenceNumber, dataQueue.dequeue().toString());
                outputQueue.enqueue(p);
                transmissionArray.add(p);
                if(sequenceBase == sequenceNumber) {
                    timer.start();
                }
                sequenceNumber++;
            } else if(dataQueue.isEmpty()) {
                timer.stop();
            }
            yield();
        }
    }

    public Queue getDataQueue() {
        return dataQueue;
    }

    public Queue getOutputQueue() {
        return outputQueue;
    }

    public void setReceiveWindow(ReceiveWindow aReceiveWindow) {
        receiveWindow = aReceiveWindow;
    }

    public void removePacket(Packet ack) {
        System.out.println(System.currentTimeMillis() + " Received ACK: " + ack.getSeq());
        sequenceBase = ack.getSeq() + 1;
        int size = transmissionArray.size()-1;
        for(int i = size; i >= 0; i--) {
            if(transmissionArray.get(i).getSeq() <= ack.getSeq()) {
                transmissionArray.remove(i);
            }
        }
        if(sequenceBase == receiveWindow.getRequestNumber()) {
            timer.stop();
        } else {
            timer.restart();
        }
    }

    private class TimerController implements ActionListener {

        public synchronized void actionPerformed(ActionEvent ev) {
            timer.start();
            try {
                for(Packet p : transmissionArray) {
                    outputQueue.enqueue(p);
                }
            } catch(ConcurrentModificationException ex) {
                ex.printStackTrace();
            }
            System.out.println(System.currentTimeMillis() + " Timeout; base=" + sequenceBase + " seq=" + sequenceNumber);
        }
    }
}
